package com.evildog.workspace.system.application.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evildog.workspace.dependencies.mybatis.base.TableLinkService;
import com.evildog.workspace.dependencies.mybatis.enums.BaseStatusEnum;
import com.evildog.workspace.dependencies.mybatis.object.BaseStatusDTO;
import com.evildog.workspace.dependencies.mybatis.object.LinkIdDTO;
import com.evildog.workspace.dependencies.mybatis.util.BaseStatusValidate;
import com.evildog.workspace.system.application.bo.MenuPermissionBO;
import com.evildog.workspace.system.application.bo.MenuPermissionTreeBO;
import com.evildog.workspace.system.application.convert.MenuPermissionConvert;
import com.evildog.workspace.system.application.dto.MenuEditPermissionDTO;
import com.evildog.workspace.system.application.entity.MenuApiPermissionLink;
import com.evildog.workspace.system.application.entity.MenuPermission;
import com.evildog.workspace.system.application.entity.RoleMenuPermissionLink;
import com.evildog.workspace.system.application.enums.MenuEnum;
import com.evildog.workspace.system.application.mapper.MenuPermissionMapper;
import com.evildog.workspace.system.application.mapper.RoleMenuPermissionLinkMapper;
import com.evildog.workspace.system.application.service.MenuApiPermissionLinkService;
import com.evildog.workspace.system.application.service.MenuPermissionService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@AllArgsConstructor
public class MenuPermissionServiceImpl extends ServiceImpl<MenuPermissionMapper, MenuPermission> implements MenuPermissionService {

    private final MenuApiPermissionLinkService menuApiPermissionLinkService;
    private final RoleMenuPermissionLinkMapper roleMenuPermissionLinkMapper;
    private final TableLinkService tableLinkService;

    @Override
    public List<MenuPermissionTreeBO> getTree() {
        List<MenuPermission> menuPermissionList = this.list(
                Wrappers.<MenuPermission>lambdaQuery()
                        .orderByAsc(MenuPermission::getParentId)
                        .orderByAsc(MenuPermission::getSort)
        );

        // key menuId value menu
        Map<Long, MenuPermissionTreeBO> menuMap = menuPermissionList.stream().collect(Collectors.toMap(MenuPermission::getId, MenuPermissionConvert.INSTANCE::convertTree));

        menuMap.values().forEach((childNode) -> {

            childNode.setDisabled(BaseStatusEnum.DISABLED.getStatus().equals(childNode.getStatus()));
            if (!childNode.getId().equals(MenuEnum.ROOT.getId())) {
                MenuPermissionTreeBO parentMenu = menuMap.get(childNode.getParentId());
                if (parentMenu.getChildren() == null) {
                    parentMenu.setChildren(new ArrayList<>());
                }
                parentMenu.getChildren().add(childNode);
            }

        });

        // 只保留根菜单并返回
        return menuMap.values().stream()
                .filter(menuPermission -> menuPermission.getId().equals(MenuEnum.ROOT.getId())).
                        collect(Collectors.toList());
    }

    @Override
    public MenuPermissionBO save(MenuEditPermissionDTO dto) {
        MenuPermission newMenuPermission = MenuPermissionConvert.INSTANCE.convert(dto);
        save(newMenuPermission);

        // 保存的菜单返回前端
        return MenuPermissionConvert.INSTANCE.convert(newMenuPermission);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(Long id) {
        removeById(id);

        // 删除与之关联的api权限 link
        tableLinkService.removeByLinkId(menuApiPermissionLinkService, MenuApiPermissionLink::getMenuPermissionId, id);

        // 删除关联的角色 link
        tableLinkService.removeByLinkId(roleMenuPermissionLinkMapper, RoleMenuPermissionLink::getMenuPermissionId, id);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateApiPermissions(Long id, LinkIdDTO linkIdDTO) {
        MenuPermission menuPermission = getById(id);
        Assert.notNull(menuPermission, "menu is null");

        List<Long> linkIds = linkIdDTO.getLinkIds();

        tableLinkService.removeByLinkId(menuApiPermissionLinkService, MenuApiPermissionLink::getMenuPermissionId, id);

        if (!linkIds.isEmpty()) {
            List<MenuApiPermissionLink> links = new ArrayList<>();
            linkIds.forEach(linkId ->
                    links.add(new MenuApiPermissionLink()
                            .setMenuPermissionId(id)
                            .setApiPermissionId(linkId)
                    ));

            menuApiPermissionLinkService.saveBatch(links);
        }

        return true;
    }

    @Override
    public MenuPermissionBO getDetailById(Long id) {
        MenuPermission menuPermission = getById(id);
        Assert.notNull(menuPermission, "menuPermission is null!");
        return MenuPermissionConvert.INSTANCE.convert(menuPermission);
    }

    @Override
    public boolean updateStatus(Long id, BaseStatusDTO baseStatus) {
        MenuPermission menuPermission = getById(id);
        Assert.notNull(menuPermission, "menuPermission is null");

        Integer status = baseStatus.getStatus();
        BaseStatusValidate.checkStatusValid(status);

        MenuPermission updateDO = new MenuPermission()
                .setId(id)
                .setStatus(status);
        return updateById(updateDO);
    }

    @Override
    public boolean updateById(Long id, MenuEditPermissionDTO dto) {
        MenuPermission oldMenuPermission = getById(id);
        Assert.notNull(oldMenuPermission, "menuPermission is null!");
        MenuPermission updateDO = MenuPermissionConvert.INSTANCE.convert(dto);
        updateDO.setId(id);
        return updateById(updateDO);
    }
}
